/**
 * Copyright (C) 2007 The AsyncMail Group <asyncmail@googlegroups.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.asyncmail.smtpserver.mina.filter;

import org.apache.commons.logging.Log;
import org.apache.mina.common.IoFilterAdapter;
import org.apache.mina.common.IoSession;
import org.springframework.beans.factory.annotation.Required;

import com.googlecode.asyncmail.common.DSNStatus;
import com.googlecode.asyncmail.smtp.SMTPRequest;
import com.googlecode.asyncmail.smtp.SMTPResponse;
import com.googlecode.asyncmail.smtp.SMTPResponseImpl;
import com.googlecode.asyncmail.smtp.SMTPRetCode;

/**
 * This Filter can be used to close the connection if the remoteserver try to
 * send commands to our Server before we sent the 220 greeting. If so, we�re
 * likely looking at a direct-to-MX spam agent which pipelines its entire SMTP
 * conversation, and will happily dump an entire spam into our mail log even if
 * later tests deny acceptance
 */
public class EarlyTalkerFilter extends IoFilterAdapter {

    private final static String GREETING_RCODE = "220";

    private final static String GREETING_SENT = "GREETING_SENT";

    private Log logger;

    private boolean useTempError = false;

    @Required
    public void setLogger(Log logger) {
        this.logger = logger;
    }

    public void useTemporyError(boolean useTempError) {
        this.useTempError = useTempError;
    }

    @Override
    public void messageSent(NextFilter arg0, IoSession arg1, Object arg2)
            throws Exception {
        if (arg1.containsAttribute(GREETING_SENT) == false) {
            if (arg2 instanceof SMTPResponse) {
                String rCode = ((SMTPResponse) arg2).getRetCode();

                if (rCode.equals(GREETING_RCODE)) {
                    logger.debug("Greeting sent");
                    arg1.setAttribute(GREETING_SENT);
                }
            } else if (arg2 instanceof String) {

                if (((String) arg2).startsWith(GREETING_RCODE)) {
                    logger.debug("Greeting sent");
                    arg1.setAttribute(GREETING_SENT);
                }
            }
        }
        arg0.messageSent(arg1, arg2);
    }

    @Override
    public void messageReceived(NextFilter arg0, IoSession arg1, Object arg2)
            throws Exception {

        if (((SMTPRequest) arg2).getCommand().equals("MAIL")
                && arg1.getAttribute(GREETING_SENT) == null) {
            logger
                    .debug("RemoteServer try to send message before we send greeting. Probarly a SPAM-Bot.");

            if (useTempError) {
                arg0.filterWrite(arg1, new WriteRequest(new SMTPResponseImpl(
                        SMTPRetCode.LOCAL_ERROR, DSNStatus.getStatus(
                                DSNStatus.TRANSIENT,
                                DSNStatus.NETWORK_DIR_SERVER)
                                + " Send commands before greeting")));
            } else {
                arg0.filterWrite(arg1, new WriteRequest(new SMTPResponseImpl(
                        SMTPRetCode.SYNTAX_ERROR_ARGUMENTS, DSNStatus
                                .getStatus(DSNStatus.PERMANENT,
                                        DSNStatus.ADDRESS_SYNTAX_SENDER)
                                + " Send commands before greeting")));
            }
        } else {
            arg0.messageReceived(arg1, arg2);
        }
    }
}
